package logs

import (
	"fmt"
	"gitee.com/injoyai/goutil/conv"
	"gitee.com/injoyai/goutil/string/color"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func NewEntity(key ...string) *Entity {
	i := ""
	if len(key) > 0 {
		i = key[0]
	}
	data := &Entity{
		key:          i,
		Name:         i,
		Tag:          nil,
		toFile:       false,
		toFilePath:   defaultPath,
		toFileLayout: defaultLayout,
		showDate:     true,
		showDir:      true,
		Color:        0,
		Level:        4,

		formatter: DefaultFormat,
	}
	data.AddMiddle(data.MiddleToConsole)
	data.AddMiddle(data.MiddleToFile)
	return data
}

// Entity [信息]2020-01-02
type Entity struct {
	key    string                        //key
	Name   string                        //名称,例如 "INFO"
	Tag    []string                      //标签
	Level  int                           //层级,默认3级
	Color  color.Color                   //颜色
	Middle []func(e *Entity, msg string) //中间件

	toFile       bool   //是否写入日志文件
	toFilePath   string //写入文件路径
	toFileLayout string //写入文件格式
	showDate     bool   //显示日期
	showDir      bool   //显示目录
	showColor    bool   //显示颜色

	formatter Formatter //格式
}

// SetFormatter 设置格式化函数
func (this *Entity) SetFormatter(f Formatter) *Entity {
	if f == nil {
		f = DefaultFormat
	}
	this.formatter = f
	return this
}

func (this *Entity) Key() string {
	return this.key
}

func (this *Entity) SetName(name string) *Entity {
	this.Name = name
	return this
}

func (this *Entity) ShowDate(b ...bool) *Entity {
	this.showDate = !(len(b) > 0 && !b[0])
	return this
}

func (this *Entity) ShowDir(b ...bool) *Entity {
	this.showDir = !(len(b) > 0 && !b[0])
	return this
}

func (this *Entity) SetTag(s ...string) *Entity {
	this.Tag = s
	return this
}

// ToFile 写入文件
func (this *Entity) ToFile(b ...bool) *Entity {
	this.toFile = !(len(b) > 0 && !b[0])
	return this
}

// ToFilePath 写入文件路径
func (this *Entity) ToFilePath(path string) *Entity {
	this.toFilePath = path
	return this
}

// ToFileLayout 默认"/2006-01-02/{name}_15.log"
func (this *Entity) ToFileLayout(layout string) *Entity {
	if len(layout) > 0 && layout[0] != '/' {
		layout = "/" + layout
	}
	this.toFileLayout = layout
	return this
}

// SetColor 设置颜色
func (this *Entity) SetColor(c color.Color) *Entity {
	this.Color = c
	return this
}

// ShowColor 显示颜色
func (this *Entity) ShowColor(b ...bool) *Entity {
	this.showColor = !(len(b) > 0 && !b[0])
	return this
}

// SetLevel 文件路径层级
func (this *Entity) SetLevel(n int) *Entity {
	this.Level = n + 4
	return this
}

func (this *Entity) SetUse(fn ...func(e *Entity, msg string)) *Entity {
	this.Middle = fn
	return this
}

func (this *Entity) AddMiddle(fn ...func(e *Entity, msg string)) *Entity {
	this.Middle = append(this.Middle, fn...)
	return this
}

// UseToConsole 中间件-控制台
func (this *Entity) UseToConsole() *Entity {
	return this.AddMiddle(this.MiddleToConsole)
}

// UseToFile 中间件-文件
func (this *Entity) UseToFile() *Entity {
	return this.AddMiddle(this.MiddleToFile)
}

// MiddleToConsole 输出到控制台
func (this *Entity) MiddleToConsole(e *Entity, msg string) {
	if this.Color != 0 && this.showColor {
		msg = color.Set(this.Color, msg)
	}
	fmt.Print(msg)
}

// MiddleToFile 输出到文件
func (this *Entity) MiddleToFile(e *Entity, msg string) {
	if this.toFile {
		if err := this.WriteToFile(msg); err != nil {
			if err := this.WriteToFile(msg); err != nil {
				fmt.Println("写入文件错误:", err)
			}
		}
	}
}

func (this *Entity) Sprint(s ...interface{}) string {
	msg := fmt.Sprint(s...)
	return this.formatter(this, msg)
	return newWrite(conv.SelectString(len(this.Name) == 0, "", fmt.Sprintf("[%s] ", this.Name)),
		func() (flag int) {
			if this.showDate {
				flag |= log.Ldate | log.Ltime
			}
			if this.showDir {
				flag |= log.Lshortfile
			}
			return
		}(), this.Level, this.Tag, s...).
		String()
}

func (this *Entity) Print(s ...interface{}) {
	msg := this.Sprint(s...)
	for _, fn := range this.Middle {
		fn(this, msg)
	}
}

func (this *Entity) WriteToFile(content string) error {
	layout := strings.ReplaceAll(this.toFileLayout, "{name}", this.Name)
	fileName := this.toFilePath + time.Now().Format(layout)
	logfile, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModeAppend|os.ModePerm)
	if err != nil {
		if strings.Contains(err.Error(), "The system cannot find the path specified") ||
			strings.Contains(err.Error(), "no such file or directory") {
			_ = os.MkdirAll(filepath.Dir(fileName), os.ModePerm)
		}
		return err
	}
	defer logfile.Close()
	_, err = logfile.Write([]byte(content))
	return err
}
